﻿using StructuredProgrammingAssignment.App_Start;
using StructuredProgrammingAssignment.Helpers;
using StructuredProgrammingAssignment.Linq;
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using System.Linq.Dynamic;

namespace StructuredProgrammingAssignment.Controllers
{
    public class ProfileController : SPStuffController
    {
		/**
		 * Get profile info of a user.
		 **/
		[System.Web.Http.AcceptVerbs("GET", "POST")]
		public Object[] GetProfile(String userId, String profileEmail) {
			try {
				SPDataContext db = new SPDataContext();

				// Authorization
				Guid parsedUserId;
				if (!Guid.TryParse(userId, out parsedUserId)) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}
				
				// Double check
				UserAccount account = (from a in db.UserAccounts
									   where a.Id.Equals(parsedUserId)
									   select a).FirstOrDefault();
				if (account == null) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Retrieve user profile
				UserAccount profile = (from a in db.UserAccounts
									  where a.Email.Equals(profileEmail)
									  select a).FirstOrDefault();
				if (profile == null) {
					return FailureResult("Invalid user profile.", "invalid user profile");
				}

				return SuccessResult(SPHelper.JsonUserProfile(profile));
			} catch (Exception e) {
				return ExceptionResult(e);
			}
		} // GetProfile

		/**
		 * Rank a user profile.
		 **/
		[System.Web.Http.AcceptVerbs("GET", "POST")]
		public Object[] Vote(String userId, String profileEmail, int rank) {
			try {
				SPDataContext db = new SPDataContext();

				// Authorization
				Guid parsedUserId;
				if (!Guid.TryParse(userId, out parsedUserId)) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}
				
				// Double check
				UserAccount account = (from a in db.UserAccounts
									   where a.Id.Equals(parsedUserId)
									   select a).FirstOrDefault();
				if (account == null) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Retrieve user profile
				UserAccount profile = (from a in db.UserAccounts
									  where a.Email.Equals(profileEmail)
									  select a).FirstOrDefault();
				if (profile == null) {
					return FailureResult("Invalid user profile.", "invalid user profile");
				}

				// Validate input
				if (rank > 5 || rank < 1) {
					return FailureResult("Trust rank must be between 1 & 5.", "input validation error");
				}

				// Ranking policies
				if (account.Id.Equals(profile.Id)) {
					return FailureResult("You cannot vote for yourself.", "voting policy error");
				}

				Ranking ranking = (from r in db.Rankings
								   where r.UserRankId.Equals(account.Id) && r.ReceiverId.Equals(profile.Id)
								   select r).FirstOrDefault();
				if (ranking != null) {
					// Update vote
					ranking.Rank = rank;
				} else {
					// Vote for user profile & return
					ranking = new Ranking() {
						UserRankId = account.Id,
						ReceiverId = profile.Id,
						Rank = rank
					};

					db.Rankings.InsertOnSubmit(ranking);
				}
				
				db.SubmitChanges();

				return SuccessResult(SPHelper.JsonUserProfile(profile));
			} catch (Exception e) {
				return ExceptionResult(e);
			}
		} // Vote

		/**
		 * Get list of stuffs from another user.
		 **/
		[System.Web.Http.AcceptVerbs("GET", "POST")]
		public Object[] GetStuffs(
			String userId,						// current user id, used for authorization
			String profileEmail,				// another user's email address

			string where = null,				// dynamic filter clause, this feature can be turn off via config
			string order = null,				// dynamic order clause, this feature can be turn off via config

			int categoryId = int.MinValue,		// filter stuffs by category

			string name = null,					// filter by name
			bool nameExact = false,				// search for exact stuff name if true

			string description = null,			// filter by description
			bool descriptionExact = false,		// search for exact stuff description if true

			DateTime? modifiedFrom = null,		// set minimum modified datetime
			DateTime? modifiedTo = null,		// set maximum modified datetime
			DateTime? createdFrom = null,		// set minimum created datetime
			DateTime? createdTo = null,			// set maximum created datetime

			decimal priceMin = decimal.MinValue,	// set minimum price
			decimal priceMax = decimal.MaxValue,	// set maximum price
			bool priceExclusive = true,			// exclusive or not

			string orderCol = "Name",			// order column
			string orderDir = "ASC",			// order direction
			int offset = 0,						// specifies the number of rows to skip
			int limit = 0						// the number of rows to be retrieved
		) {
			try {
				SPDataContext db = new SPDataContext();

				// Authorization
				Guid parsedUserId;
				if (!Guid.TryParse(userId, out parsedUserId)) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Double check
				UserAccount account = (from a in db.UserAccounts
									   where a.Id.Equals(parsedUserId)
									   select a).FirstOrDefault();
				if (account == null) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Check for user profile
				UserAccount profile = (from a in db.UserAccounts
									   where a.Email.Equals(profileEmail)
									   select a).FirstOrDefault();
				if (profile == null) {
					return FailureResult("Invalid user profile.", "invalid user profile");
				}

				// Retrieve list of stuffs
				var stuffs = (from s in db.UserStuffs
							  where s.UserAccount.Email.Equals(profileEmail)
							  select s);

				// Return
				return GetStuffs(stuffs.ToList(), where, order, categoryId, name, nameExact, description, descriptionExact, modifiedFrom, modifiedTo, createdFrom, createdTo, priceMin, priceMax, priceExclusive, orderCol, orderDir, offset, limit);
			} catch (Exception e) {
				return ExceptionResult(e);
			}
		} // GetStuffs

    } // UserProfileController
}
